package net.thxjj.mobileServer.service.impl;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.thxjj.mobileServer.dao.*;
import net.thxjj.mobileServer.entity.*;
import net.thxjj.mobileServer.service.IUserService;
import net.thxjj.mobileServer.util.JWTUtils;
import net.thxjj.mobileServer.util.ParameterMap;
import net.thxjj.mobileServer.util.SHA;
import net.thxjj.mobileServer.util.Tools;
import net.thxjj.sitermodel.*;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Service
public class UserService implements IUserService {
    private Logger log = Logger.getLogger(this.getClass());

    @Autowired
    private UserDao userDao;

    @Autowired
    private RelationDao relationDao;

    @Autowired
    private CompanyDao companyDao;

    @Autowired
    private RoomAndPlaceDao roomAndPlaceDao;

    @Autowired
    private PinCodeDao pinCodeDao;


    @Override
    public HashMap<String,Object> Login(ParameterMap pm) {

        try{
            String psw = pm.getString("password");
            String userName = pm.getString("username");
            String login_type = pm.getString("login_type");
            String rip = pm.getString("rip");
            String pid = pm.getString("pid");
            String app_tid = pm.getString("app_tid");
            if(!Tools.isNumber(login_type)){
                return ResponseModel.getModel(ResultEnum.LOGIN_TYPE_IS_EMPTY_OR_ERROR,null);
            }
            else if(Tools.isEmpty(pid)){
                return ResponseModel.getModel(ResultEnum.PARAMS_EMPTY_ERROR,null);
            }
            else if(Tools.isEmpty(userName)){
                return ResponseModel.getModel(ResultEnum.USERNAME_IS_EMPTY,null);
            }else if(Tools.isEmpty(psw)){
                return ResponseModel.getModel(ResultEnum.PASSWORD_IS_EMPTY,null);
            }else{


                if(companyDao.getCompanyByPid(pid)==null){
                    return ResponseModel.getModel(ResultEnum.APPTID_IS_NOT_EXIST,null);
                }


                long d = Integer.parseInt(login_type);
                if(d<0 || d>1){
                    return ResponseModel.getModel(ResultEnum.LOGIN_TYPE_IS_EMPTY_OR_ERROR,null);
                }


                try {
                        psw = SHA.encryptSHA(psw);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    pm.put("password",psw);

                    ParameterMap parameterMap = userDao.getMobileUserByPwd(pm);

                    if(parameterMap==null){
                        return ResponseModel.getModel(ResultEnum.USERNAME_OR_PASSWORD_ERROR,null);
                    }else{



                        long sys_millon = System.currentTimeMillis();
                        long user_id = Integer.parseInt(parameterMap.getString("user_id"));
                        String username = parameterMap.getString("username");
                        long expired_access = sys_millon + GenieResum.ACCESS_TOKEN_EXPIRED_SECOND;
                        long expired_refresh = sys_millon + GenieResum.REFRESH_TOKEN_EXPIRED_SECOND;


                        //生成access_token
                        ParameterMap parameterMap_acc = new ParameterMap();
                        parameterMap_acc.put("user_id",user_id);
                        parameterMap_acc.put("username",username);
                        parameterMap_acc.put("login_time",sys_millon);
                        parameterMap_acc.put("expired",expired_access);
                        String ad = JSONObject.toJSON(parameterMap_acc).toString();
                        String access_token =  JWTUtils.ProduceToken(ad);

                        //生成refresh_token
                        ParameterMap parameterMap_refresh = new ParameterMap();
                        parameterMap_refresh.put("expired",expired_refresh);
                        parameterMap_refresh.put("login_time",sys_millon);
                        parameterMap_refresh.put("username",username);
                        parameterMap_refresh.put("user_id",user_id);
                        String ad2 = JSONObject.toJSON(parameterMap_refresh).toString();
                        String refresh_token =  JWTUtils.ProduceToken(ad2);


                        ParameterMap de = new ParameterMap();
                        de.put("user_id",Integer.parseInt(parameterMap.getString("user_id")));
                        de.put("app_tid",app_tid);
                        ParameterMap parameterMap2 = userDao.getUserTokenInfo(de);
                        if(parameterMap2==null){
                            parameterMap2 = new ParameterMap();
                            parameterMap2.put("user_id",user_id);
                            parameterMap2.put("access_token",access_token);
                            parameterMap2.put("refresh_token",refresh_token);
                            parameterMap2.put("login_time",sys_millon);
                            parameterMap2.put("refresh_time",sys_millon);
                            parameterMap2.put("login_type",login_type);
                            parameterMap2.put("ip",rip);
                            parameterMap2.put("app_tid",app_tid);
                            userDao.addToken(parameterMap2);
                        }else{
                            parameterMap2.put("access_token",access_token);
                            parameterMap2.put("refresh_token",refresh_token);
                            parameterMap2.put("login_time",sys_millon);
                            parameterMap2.put("refresh_time",sys_millon);
                            parameterMap2.put("login_type",login_type);
                            parameterMap2.put("ip",rip);
                            parameterMap2.put("app_tid",app_tid);
                            userDao.updateToken(parameterMap2);
                        }
                        parameterMap.put("expired_in",GenieResum.ACCESS_TOKEN_EXPIRED_SECOND);
                        parameterMap.put("access_token",access_token);
                        parameterMap.put("refresh_token",refresh_token);

                        return ResponseModel.getModel(ResultEnum.SUCCESS,parameterMap);
                    }



            }
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            e.printStackTrace();
            log.error("error:"+e.getMessage(), e);
            return ResponseModel.getModel(ResultEnum.ERROR, null);
        }




    }


    @Override
    public MobileUser getUserInfoById(long user_id) {
        return userDao.getUserInfoByUserId(user_id);
    }

    @Override
    public ParameterMap getUserSnapshot(String access_token) {
        return userDao.getUserInfoByTokenNetty(access_token);
    }


    @Override
    public HashMap<String, Object> changePassword(ParameterMap pm) {
        // TODO Auto-generated method stub
        try {
            ParameterMap map = userDao.getMobileUserByPwdAndUserId(pm);
            if(map==null){
                return ResponseModel.getModel(ResultEnum.USERNAME_OR_PASSWORD_ERROR,null);
            }else{
                userDao.updatePassword(pm);
            }
        } catch (Exception e) {
            log.error("error:" + e.getMessage(), e);
            return ResponseModel.getModel(ResultEnum.ERROR, null);
        }
        return ResponseModel.getModel(ResultEnum.SUCCESS, null);
    }

    @Override
    public Object refreshToken(String refresh_token,long user_id) {

        try {
            ParameterMap mmap = userDao.getUserByRefreshToken(refresh_token,user_id);
            if(mmap==null){
                return ResponseModel.getModel(ResultEnum.REFRESH_TOKEN_IS_NOT_EXIST, null);
            }else{
                long login_time = Long.parseLong(mmap.getString("login_time"));

                long sys_millon = System.currentTimeMillis();

                if(sys_millon>login_time+GenieResum.REFRESH_TOKEN_EXPIRED_SECOND){
                    return ResponseEntity.status(401);
                }else{
                    String app_tid = mmap.getString("app_tid");
                    long expired_access = sys_millon + GenieResum.ACCESS_TOKEN_EXPIRED_SECOND;
                    //生成新的access_token
                    ParameterMap parameterMap_acc = new ParameterMap();
                    parameterMap_acc.put("user_id",user_id);
                    parameterMap_acc.put("refresh_time",sys_millon);
                    parameterMap_acc.put("expired",expired_access);
                    String ad = JSONObject.toJSON(parameterMap_acc).toString();
                    String access_token =  JWTUtils.ProduceToken(ad);

                    ParameterMap p = new ParameterMap();
                    p.put("user_id",user_id);
                    p.put("refresh_time",sys_millon);
                    p.put("access_token",access_token);
                    p.put("app_tid",app_tid);
                    userDao.updateToken(p);

                    ParameterMap p2 = new ParameterMap();
                    p2.put("refresh_token",refresh_token);
                    p2.put("access_token",access_token);
                    p2.put("user_id",user_id);
                    p2.put("expired",GenieResum.ACCESS_TOKEN_EXPIRED_SECOND);

                    return ResponseModel.getModel(ResultEnum.SUCCESS, p2);
                }



            }
        } catch (Exception e) {
            log.error("error:" + e.getMessage(), e);
            return ResponseModel.getModel(ResultEnum.ERROR, null);
        }
    }



    @Override
    public List<Device> getBindDeviceList(long user_id) {
        List<String> devTids = relationDao.getUserBindDeviceList(user_id);

        List<Device> list1 = new ArrayList<>();
        for (int i=0;i<devTids.size();i++){
            String devTid = devTids.get(i);
            Device map = userDao.getDeviceInfo(devTid,null,null);
            list1.add(map);
        }

        return list1;
    }

    @Transactional(rollbackFor=Exception.class)
    @Override
    public HashMap<String, Object> insertRelation(String device_id,String bind_key, long user_id) {

        if(Tools.isEmpty(device_id)||Tools.isEmpty(bind_key)){
            return ResponseModel.getModel(ResultEnum.PARAMS_EMPTY_ERROR,null);
        }

        Device map = userDao.getDeviceInfo(device_id,bind_key,null);

        if(map==null){
            return ResponseModel.getModel(ResultEnum.DEVICE_NOT_EXIST_ERROR,null);
        }

        try {
            relationDao.deleteAdminRelation(device_id);
            Relation touristRelation = new Relation().setDeviceId(device_id).setBindUser(user_id).setBindType(0);
            relationDao.insertRelation(touristRelation);

            return ResponseModel.getModel(ResultEnum.SUCCESS,map);
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseModel.getModel(ResultEnum.ERROR,null);
        }

    }

    @Override
    public HashMap<String, Object> unbind(String device_id, String bind_key, long user_id) {

        if(Tools.isEmpty(device_id)||Tools.isEmpty(bind_key)){
            return ResponseModel.getModel(ResultEnum.PARAMS_EMPTY_ERROR,null);
        }

        Device map = userDao.getDeviceInfo(device_id,bind_key,null);

        if(map==null){
            return ResponseModel.getModel(ResultEnum.DEVICE_NOT_EXIST_ERROR,null);
        }

        Relation touristRelation = relationDao.selectRelationDeviceUser(user_id,device_id);
        if(touristRelation==null){
            return ResponseModel.getModel(ResultEnum.DEVICE_IS_NOT_BIND_TO_YOU_ERROR,null);
        }

        try {
            if(touristRelation.getBindType()==1){
                relationDao.deleteRelation(device_id,user_id);
            }else{
                relationDao.deleteAdminRelation(device_id);
            }
            return ResponseModel.getModel(ResultEnum.SUCCESS,null);
        }catch (Exception e){
            return ResponseModel.getModel(ResultEnum.ERROR,null);
        }

    }


    @Transactional(rollbackFor=Exception.class)
    @Override
    public HashMap<String, Object> cancelAccount(long user_id) {
        try {

            List<Place> placeBeans = roomAndPlaceDao.getPlaces(user_id);
            for (int i=0;i<placeBeans.size();i++){
                Place placeBean = placeBeans.get(i);
                List<Room> roomBeanList = roomAndPlaceDao.getRooms(placeBean.getPlaceId());
                for (int j=0;j<roomBeanList.size();j++){
                    Room roomBean = roomBeanList.get(j);
                    roomAndPlaceDao.deleteRoomRelationByRoomId(roomBean.getRoomId());
                }
                roomAndPlaceDao.deleteRoomByPlaceId(placeBean.getPlaceId());
            }

            roomAndPlaceDao.deletePlaceByUserId(user_id);
            relationDao.deleteRelationByUser(user_id);
            userDao.deleteMobileUser(user_id);
            userDao.deleteMobileUserToken(user_id);
            return ResponseModel.getModel(ResultEnum.SUCCESS,null);
        }catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseModel.getModel(ResultEnum.ERROR,null);
        }
    }

    @Override
    public List<Place> getPlaceAndRooms(long user_id) {

        List<Place> placeBeanList = roomAndPlaceDao.getPlaces(user_id);
        for (int i=0;i<placeBeanList.size();i++){
            Place placeBean = placeBeanList.get(i);
            List<Room> roomBeanList = roomAndPlaceDao.getRooms(placeBean.getPlaceId());
            for (int j=0;j<roomBeanList.size();j++){
                Room roomBean = roomBeanList.get(j);
                List<String> devices = roomAndPlaceDao.getRoomRelations(roomBean.getRoomId());
                roomBean.setDeviceList(devices);
            }
            placeBean.setRoomBeanList(roomBeanList);
        }


        return placeBeanList;
    }

    @Override
    public HashMap<String, Object> getPinCode(long user_id,String ssid) {
        try {
            String pincode = PrimaryKeyGeneratorTool.pincodeGenerator();
            log.info("生成pincode："+pincode);
            PinCodeBean pinCodeBean = new PinCodeBean().setUserId(user_id).setPinCode(pincode).setCreateTime(System.currentTimeMillis()).setSsid(ssid);
            pinCodeDao.insertPinCode(pinCodeBean);
            ParameterMap map  = new ParameterMap();
            map.put("pinCode",pincode);
            map.put("shadowName","shadowName");
            return ResponseModel.getModel(ResultEnum.SUCCESS,map);
        }catch (Exception e){
            return ResponseModel.getModel(ResultEnum.ERROR,null);
        }
    }

    @Override
    public HashMap<String,Object> getNewDeviceList(String pincode,long user_id) {

      PinCodeBean pinCodeBean =  pinCodeDao.getPinCodeBean(pincode,user_id);

      ArrayList<Device> list = new ArrayList<>();

      if(pinCodeBean!=null){
          long currentTime = System.currentTimeMillis();
          if(!Tools.isEmpty(pinCodeBean.getDeviceId()) && (currentTime-pinCodeBean.getCreateTime())<1000*600 ){
              Device map = userDao.getDeviceInfo(pinCodeBean.getDeviceId(),null,null);
              if(map!=null){
                  map.setOwned(1L);
                  list.add(map);
                  pinCodeDao.updatePincodeStatus(pincode,user_id);
              }
          }
      }

        return ResponseModel.getModel(ResultEnum.SUCCESS,list);
    }
}
